home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mmdf / mmdf-IIb.43 / src / deliver / ch_io.c next >
Encoding:
C/C++ Source or Header  |  1990-02-28  |  12.3 KB  |  465 lines

  1. #include "util.h"
  2. #include "mmdf.h"
  3.  
  4. /*
  5.  *     MULTI-CHANNEL MEMO DISTRIBUTION FACILITY  (MMDF)
  6.  *
  7.  *
  8.  *     Copyright (C) 1979,1980,1981  University of Delaware
  9.  *
  10.  *     Department of Electrical Engineering
  11.  *     University of Delaware
  12.  *     Newark, Delaware  19711
  13.  *
  14.  *     Phone:  (302) 738-1163
  15.  *
  16.  *
  17.  *     This program module was developed as part of the University
  18.  *     of Delaware's Multi-Channel Memo Distribution Facility (MMDF).
  19.  *
  20.  *     Acquisition, use, and distribution of this module and its listings
  21.  *     are subject restricted to the terms of a license agreement.
  22.  *     Documents describing systems using this module must cite its source.
  23.  *
  24.  *     The above statements must be retained with all copies of this
  25.  *     program and may not be removed without the consent of the
  26.  *     University of Delaware.
  27.  *     
  28.  *
  29.  *     version  -1    David H. Crocker    March   1979
  30.  *     version   0    David H. Crocker    April   1980
  31.  *     version   1    David H. Crocker    October 1981
  32.  *
  33.  */
  34. /*  CH_IO:  Channel invocation & communication                          */
  35.  
  36. /*  Jun 80 Dave Crocker     fix ch_close fildes setting to -1
  37.  *  Nov 80 Dave Crocker     convert to ch_struct pointer from ch_code
  38.  *  Jul 81 Dave Crocker     ch_rdrec a little cleaner on error handling
  39.  */
  40.  
  41. #define TIMEOUT 3600             /* 60 minute sanity timer on channel IO */
  42.  
  43. #include "ch.h"
  44. #include <signal.h>
  45. #include "nexec.h"
  46.  
  47. extern char pgm_bakgrnd;
  48. extern LLog *logptr;
  49. extern char *chndfldir;
  50. extern int  *regfdary;           /* for nexec                         */
  51. extern int  numfds;
  52.  
  53. extern char *blt();
  54.  
  55. LOCFUN ch_rrec(), ch_exec();
  56.  
  57. Chan    *ch_curchan;               /* currently active channel program   */
  58. RP_Buf ch_rp;         /* last channel reply text            */
  59.  
  60. /*  ***************  (ch_) COMMUNICATE WITH CHANNEL  ***************** */
  61.  
  62. LOCVAR FILE *ch_outfp,            /* output file handle for chan */
  63.        *ch_infp;              /* input file handle for channel */
  64.  
  65. LOCVAR int    ch_child;           /* Process id of channel program      */
  66. LOCVAR sigtype (* ch_opipe) ();   /* old pipe action value              */
  67.  
  68. LOCFUN sigtype
  69. ch_catch ()              /* catch interrupt                    */
  70. {
  71. }
  72.  
  73. ch_end (type)                     /* get ready to send mail to channels */
  74.     int type;
  75. {                                 /* NOTOK => close; 0 => addr list end */
  76. #ifdef DEBUG
  77.     ll_log (logptr, LLOGBTR, "ch_end (%d)", type);
  78. #endif
  79.  
  80.     return (ch_sbend (type));
  81. }
  82. /* */
  83.  
  84. ch_sbinit (newchan)               /* "get" a specific channel           */
  85. register Chan  *newchan;          /* pointer to chan structure          */
  86. {                                 /* NOTOK => close; 0 => addr list end */
  87.     int temp;
  88.  
  89. #ifdef DEBUG
  90.     ll_log (logptr, LLOGBTR, "ch_open(%s)", newchan -> ch_name);
  91. #endif
  92.  
  93.     if (newchan == ch_curchan)
  94.     return (RP_OK);           /* already have the channel opened    */
  95.  
  96.     if (!pgm_bakgrnd && (newchan -> ch_access & DLVRBAK))
  97.     return (RP_NOOP);         /* not allowed unless background      */
  98.  
  99.     if (ch_curchan != OK)         /* already have chan -> get rid of it */
  100.     ch_end (OK);
  101.  
  102.     newchan -> ch_access |= DLVRDID; /* note that we did this channel      */
  103.  
  104.     if ((temp = ch_exec (newchan)) == RP_OK)
  105.     ch_curchan = newchan;
  106.  
  107.     ch_opipe = signal (SIGPIPE, ch_catch);
  108.     signal (SIGALRM, ch_catch);
  109.     return (temp);
  110. }
  111. /* */
  112.  
  113. ch_sbend (type)               /* free the channel                   */
  114. int type;                     /* clean ending / abort               */
  115. {
  116.     register int status;
  117.  
  118. #ifdef DEBUG
  119.     ll_log(logptr, LLOGBTR, "ch_end (%d)", type);
  120. #endif
  121.  
  122.     if (ch_child == 0)            /* don't have one                     */
  123.     return (OK);
  124.  
  125.     switch (type)
  126.     {
  127.     case NOTOK:               /* ABORTING;  try to kill child       */
  128.         ll_log (logptr, LLOGTMP, "Trying to kill child  '%s' pid = (%d)",
  129.             ch_curchan -> ch_name, ch_child);
  130.         kill (ch_child, SIGKILL);
  131.         goto closeit;
  132.  
  133.     case OK:                  /* normal end; just eof the pipes     */
  134.         ch_wrec ("end");      /* say goodbye */
  135.  
  136.     closeit:
  137.         if (ch_outfp == (FILE *) EOF)
  138.             return(RP_OK);    /* ch_wrec might have already closed  */
  139.  
  140.         fclose (ch_outfp);
  141.         fclose (ch_infp);
  142.  
  143.         ch_outfp =            /* flag i/o ports as closed           */
  144.         ch_infp = (FILE *) EOF;
  145.         signal (SIGPIPE, ch_opipe);
  146.                   /* probably set it back to abort      */
  147.         break;
  148.  
  149.     default:
  150.         err_abrt (RP_NCMD, "Illegal closedest call (%d)", type);
  151.     }
  152.  
  153.     status = pgmwait (ch_child);  /* pickup child's stats               */
  154.     if (status == NOTOK)          /* abnormal proces termination        */
  155.     ll_err (logptr, LLOGTMP, "(%s) child NOTOK", ch_curchan -> ch_name);
  156.  
  157.     if (rp_gbval (status) == RP_BNO)
  158.     ll_log (logptr, LLOGTMP, "(%s) child (%s)",
  159.             rp_valstr (status), ch_curchan -> ch_name);
  160.                   /* log major error returns only       */
  161.  
  162.     ch_curchan = OK;              /* mark current channel as "none"     */
  163.     ch_child = 0;                 /* don't have one any more            */
  164.     return (RP_OK);
  165. }
  166. /* */
  167.  
  168. ch_rrply (valstr, len)     /* read reply from channel            */
  169.     RP_Buf *valstr;
  170.     int *len;
  171. {
  172.     int     result;
  173.  
  174. #ifdef notdef
  175.     ll_log(logptr, LLOGBTR, "ch_rrply()");
  176. #endif
  177.  
  178.     ch_rp.rp_val = RP_NOOP;
  179.     (void) strcpy (ch_rp.rp_line, "(No reason given)");
  180.  
  181.     result = ch_rrec ((char *) valstr, len);
  182.  
  183. #ifdef RUNALON
  184.     switch (valstr -> rp_val)
  185.     {
  186.     case 'y':
  187.         result = RP_OK;
  188.         break;
  189.     case 'n':
  190.         result = RP_NO;
  191.         break;
  192.     case 'a':
  193.         result = RP_AOK;
  194.         break;
  195.     case 'd':
  196.         result = RP_DOK;
  197.         break;
  198.     case 'm':
  199.         result = RP_MOK;
  200.         break;
  201.     case 't':
  202.         result = RP_TIME;
  203.         break;
  204.     case 'c':
  205.         result = RP_NET;
  206.     }
  207. #endif
  208.  
  209.     *len -= 1;
  210.     if ((*len > 0) && (*len <= RP_LINEBUF_MAX)) {
  211.     blt (valstr -> rp_line, ch_rp.rp_line, *len);
  212.     ch_rp.rp_line[*len] = '\0';
  213.     }
  214.     else
  215.     *len = 0;
  216.  
  217.  
  218. #ifdef DEBUG
  219.     ll_log(logptr, LLOGFTR, "reply: (%s) '%s'",
  220.         rp_valstr (valstr -> rp_val), valstr -> rp_line);
  221. #endif
  222.  
  223.     ch_rp.rp_val = valstr -> rp_val;
  224.  
  225.     if (rp_isbad (result))
  226.     return (result);
  227.  
  228.     return (RP_OK);
  229. }
  230. /* */
  231.  
  232. ch_wrec (str)                     /* send info to channel               */
  233. char    str[];                    /* string to send                     */
  234. {
  235. #ifdef notdef
  236.     ll_log(logptr, LLOGBTR, "ch_wrec ()");
  237. #endif
  238.                   /* default error message              */
  239.     if (ch_curchan == OK)         /* channel isn't really there         */
  240.     return (RP_DHST);
  241.  
  242. #ifdef DEBUG
  243.     ll_log(logptr, LLOGFTR, "sending:  '%s'", str);
  244. #endif
  245. #ifdef RUNALON
  246.     printx ("Channel output:  '%s'\n", str);
  247. #else
  248.     if (setjmp (timerest)) {
  249.     ll_err (logptr, LLOGTMP, "(%s) output err to channel",
  250.         ch_curchan -> ch_name);
  251.     ch_sbend (NOTOK);         /* close it                           */
  252.     return (RP_NET);          /* class it as a "network" error      */
  253.     }
  254.     s_alarm (TIMEOUT);
  255.     if (str)                  /* send it to channel                 */
  256.     fputs (str, ch_outfp);
  257.  
  258.     putc ('\0', ch_outfp);
  259.     fflush (ch_outfp);    /* This causes real IO */
  260.     s_alarm (0);
  261.  
  262.     if (ferror (ch_outfp))
  263.     {
  264.     ll_err (logptr, LLOGTMP, "(%s) output err to channel",
  265.         ch_curchan -> ch_name);
  266.     ch_sbend (NOTOK);         /* close it                           */
  267.     return (RP_NET);          /* class it as a "network" error      */
  268.     }
  269.     return (RP_OK);
  270. #endif
  271. }
  272. /* */
  273.  
  274. LOCFUN
  275.     ch_rrec (rplyline, len)    /* read reply from channel            */
  276.     char *rplyline;
  277.     int *len;
  278. {
  279.     int     result;
  280.     char *valstr;
  281.  
  282. #ifdef notdef
  283.     ll_log(logptr, LLOGBTR, "ch_rrec()");
  284. #endif
  285. #ifdef RUNALON
  286.     printx ("Chrcv:  ");
  287. #endif
  288.  
  289.     if (setjmp (timerest)) {
  290.     ll_err (logptr, LLOGTMP, "(%s) read err from channel",
  291.             ch_curchan -> ch_name);
  292.     ch_end (NOTOK);             /* probably not there, anyhow         */
  293.     return (RP_NET);
  294.     }
  295.     s_alarm (TIMEOUT);
  296.     result = RP_OK;
  297.     rplyline[0] = getc (ch_infp); /* one-char rp.h reply value          */
  298.     s_alarm (0);
  299.  
  300.     *len = 1;
  301.     if (feof (ch_infp))
  302.     {
  303.     ll_log (logptr, LLOGTMP, "(%s) premature channel eof",
  304.             ch_curchan -> ch_name);
  305.     ch_end (NOTOK);             /* probably not there, anyhow         */
  306.     return (RP_NET);
  307.     }
  308.     if (ferror (ch_infp))
  309.     {
  310.     ll_err (logptr, LLOGTMP, "(%s) read err from channel",
  311.             ch_curchan -> ch_name);
  312.     ch_end (NOTOK);             /* probably not there, anyhow         */
  313.     return (RP_NET);
  314.     }
  315.  
  316. #ifdef RUNALON
  317.     switch (rplyline[0])
  318.     {
  319.     case 'y':
  320.         replyline[0] = RP_OK;
  321.         break;
  322.     case 'n':
  323.         replyline[0] = RP_NO;
  324.         break;
  325.     case 'a':
  326.         replyline[0] = RP_AOK;
  327.         break;
  328.     case 'd':
  329.         replyline[0] = RP_DOK;
  330.         break;
  331.     case 'm':
  332.         replyline[0] = RP_MOK;
  333.         break;
  334.     case 't':
  335.         replyline[0] = RP_TIME;
  336.         break;
  337.     case 'c':
  338.         replyline[0] = RP_NET;
  339.     }
  340. #endif
  341.     if (setjmp (timerest)) {
  342.     ll_err (logptr, LLOGTMP, "(%s) Channel died", ch_curchan -> ch_name);
  343.     *len += 1;
  344.     return (rplyline[0] = result = RP_NET);
  345.     }
  346.     s_alarm (TIMEOUT);
  347.     if ((*len = gcread (ch_infp, &rplyline[1], LINESIZE - 2, "\n\000\377"))
  348.             == 0)
  349.     {
  350.     ll_err (logptr, LLOGTMP, "(%s) Channel died", ch_curchan -> ch_name);
  351.     rplyline[0] =
  352.         result = RP_NET;
  353.     }
  354.     s_alarm (0);
  355.  
  356.     valstr = rp_valstr (rplyline[0]);
  357.     if (*valstr == '*')
  358.     {
  359.     ll_log (logptr, LLOGFAT, "(%s) (%s) '%s'",
  360.         ch_curchan -> ch_name, valstr, &rplyline[1]);
  361.     return (RP_RPLY);
  362.     }
  363.  
  364.     *len += 1;
  365. #ifdef DEBUG
  366.     ll_log(logptr, LLOGFTR, "record: (%s) '%s'", valstr, &rplyline[1]);
  367. #endif
  368.     return (result);
  369. }
  370. /* */
  371.  
  372. LOCFUN
  373.     ch_exec (thechan)         /* invoke process which "is" channel  */
  374. Chan   *thechan;      /* channel descriptor structure       */
  375. {
  376.     register  tmp;
  377.     int     nampipe[2];           /* to xmit process for addr name        */
  378.     int     respipe[2];           /* from xmit process, for responses     */
  379.     int     oldpid;               /* parent pid */
  380.     char    temppath[128];
  381.     char    arg1[10];             /* fd for input (names/addrs)         */
  382.     char    arg2[10];             /* fd for output (responses)          */
  383.     char    arg3[20];             /* options                            */
  384.  
  385. #ifdef notdef
  386.     ll_log(logptr, LLOGBTR, "ch_exec()");
  387. #endif
  388. #ifdef RUNALON
  389.     printx ("Forking %s\n", thechan -> ch_name);
  390.     ch_infp = fdopen (0, "r");
  391.     ch_outfp = fdopen (1, "w");
  392.  
  393.     return (RP_OK);               /* debug mode                         */
  394. #endif;
  395.  
  396.     if (pipe (nampipe) < OK)
  397.     {
  398.     ll_err(logptr, LLOGTMP, "problem with 1st ch_exec pipe");
  399.     return (RP_NO);
  400.     }
  401.     if (pipe (respipe) < OK)
  402.     {
  403.     ll_err(logptr, LLOGTMP, "problem with 2d ch_exec pipe");
  404.     (void) close (nampipe[0]);
  405.     (void) close (nampipe[1]);
  406.     return (RP_NO);
  407.     }
  408.     sprintf (arg1, "%d", nampipe[0]);
  409.     sprintf (arg2, "%d", respipe[1]);
  410.     arg3[0] = '\0';
  411.     if( domsg == TRUE )
  412.     strcat( arg3, "w" );
  413.  
  414.     regfdary[0] = 0;              /* must keep open, in case of POBox   */
  415.     regfdary[1] = 1;              /*   or other interaction with caller */
  416.  
  417.     for(tmp=2; tmp < numfds; regfdary[tmp++] = CLOSEFD);
  418.  
  419.     regfdary[nampipe[0]] = nampipe[0];
  420.     regfdary[respipe[1]] = respipe[1];
  421.  
  422.     getfpath (thechan -> ch_ppath, chndfldir, temppath);
  423.  
  424. #ifdef DEBUG
  425.     ll_log(logptr, LLOGBTR, "[%s]'%s' ('%s','%s', '%s')",
  426.         temppath, thechan -> ch_name, arg1, arg2, arg3);
  427.  
  428. #endif
  429.     ll_close (logptr);            /* since we are about to fork()       */
  430.     fflush (stdout);
  431.     fflush (stderr);
  432.     oldpid = getpid ();
  433.  
  434.     ch_child = nexecl (FRKEXEC, FRKERRR, regfdary, temppath,
  435.             thechan -> ch_name, arg1, arg2, arg3, (char *)0);
  436.  
  437.     (void) close (nampipe[0]);     /* Close other end of pipes */
  438.     (void) close (respipe[1]);
  439.     if (ch_child == NOTOK)        /* didn't get the child               */
  440.     {
  441.     ll_err (logptr, LLOGFAT, "Unable to run '%s'", thechan -> ch_ppath);
  442.     ch_child = 0;
  443.     (void) close (nampipe[1]);       /* Close other end of pipes     */
  444.     (void) close (respipe[0]);
  445.     if (getpid () == oldpid)
  446.         return (RP_NO);       /* still the parent => fork() error   */
  447.     else
  448.         exit (RP_MECH);      /* must be child                       */
  449.     }
  450.                   /* clean up regfd arrary for future   */
  451.     regfdary[nampipe[0]] = -1;
  452.     regfdary[respipe[1]] = -1;
  453.  
  454.     ch_infp = fdopen (respipe[0], "r");
  455.     ch_outfp = fdopen (nampipe[1], "w");
  456.  
  457.     printx ("[ Accessing %s (%s)]\n", 
  458.         thechan -> ch_name, thechan -> ch_show);
  459.     ll_log (logptr, LLOGPTR, "[ %s ] (r%d,w%d)",
  460.         thechan -> ch_name, respipe[0], nampipe[1]);
  461.  
  462.     return (RP_OK);
  463. }
  464.  
  465.